/*
 * LexicalAnalyzer.cpp
 *
 *  Created on: 13/04/2009
 *      Author: evellyn, tamer, t�rsis
 */

#include "LexicalAnalyzer.h"
#include "Token.h"
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>
#include <cctype>
#include <list>

using namespace std;

LexicalAnalyzer::LexicalAnalyzer(string path) {

	source.open(path.c_str());

	if (!source.good()) {
		cerr << "Bad Source!";
		exit(1);
	}

	columnPos = 1;
	linePos = 0;
	controlPointer = 0;

}

list<Token> LexicalAnalyzer::scan() {

	const int MAX_LENGHT = 1024;
	char buffer[MAX_LENGHT];

	ofstream tokensArchive;
	tokensArchive.open("tokens.tk", ios::trunc);

	while (!source.eof()) {

		source.getline(buffer, MAX_LENGHT);
		line = buffer;
		linePos++;
		controlPointer = 0;

		while (controlPointer != line.size() + 1) {

			if (isCommentSymbol(line[controlPointer])) {
				break;
			}

			else if (isspace(line[controlPointer]) || line[controlPointer]
					== '\0') {
				skipSpace();
			}

			else if (isalpha(line[controlPointer])) {
				token.setToken(linePos, columnPos, 0, getName());
				listOfTokens.push_back(token);
				tokensArchive << token.getToken() << "\n";
			}

			else if (isdigit(line[controlPointer]) || line[controlPointer]
					== '.') {
				string tmp = getDigit();

				if (tmp.compare(".") == 0) {
					cerr << "Error: Invalid Character '.', line " << linePos
							<< line[controlPointer] << endl;
					exit(1);
				}

				token.setToken(linePos, columnPos, 1, tmp);
				listOfTokens.push_back(token);
				tokensArchive << token.getToken() << "\n";
			}

			else if (isOperator(line[controlPointer])) {
				token.setToken(linePos, columnPos, 2, getOperator());
				listOfTokens.push_back(token);
				tokensArchive << token.getToken() << "\n";
			}

			else if (isDelimiter(line[controlPointer])) {
				token.setToken(linePos, columnPos, 3, getDelimiter());
				listOfTokens.push_back(token);
				tokensArchive << token.getToken() << "\n";
			}

			else if (isCharacterDelimiter(line[controlPointer])) {
				token.setToken(linePos, columnPos, 4, getCharacterDelimiter());
				listOfTokens.push_back(token);
				tokensArchive << token.getToken() << "\n";
			}

			else {
				cerr << "Error: Invalid Character '" << line[controlPointer]
						<< "' , line " << linePos << endl;
				exit(1);
			}
		}
	}
	source.close();

	return listOfTokens;
}

bool LexicalAnalyzer::isOperator(char c) {
	return (c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c
			== '%' || c == '>' || c == '<' || c == '!' || c == '=');
}

bool LexicalAnalyzer::isCommentSymbol(char c) {
	return c == '#';
}

bool LexicalAnalyzer::isDelimiter(char c) {
	return (c == '{' || c == '}' || c == '[' || c == ']' || c == '(' || c
			== ')' || c == ',' || c == ';');
}

bool LexicalAnalyzer::isCharacterDelimiter(char c) {
	return (c == '"' || c == '\'');
}

char LexicalAnalyzer::getNext() {
	controlPointer++;
	return line[controlPointer];
}

string LexicalAnalyzer::getName() {
	columnPos = controlPointer;
	char actual = getNext();

	while (true) {
		if (isalpha(actual) || actual == '_')
			actual = getNext();
		else
			break;
	}
	return line.substr(columnPos, controlPointer - columnPos);
}

string LexicalAnalyzer::getDigit() {
	columnPos = controlPointer;
	char actual = line[controlPointer];

	// This case accepts a (. ,{digit}+)
	if (actual == '.') {
		actual = getNext();
		while (true) {
			if (isdigit(actual))
				actual = getNext();
			else
				break;
		}
	} else {
		while (true) {
			actual = getNext();
			if (isdigit(actual) || actual == '.') {
				//This accepts a ({digit}, '.' , {digit})
				if (actual == '.') {
					while (isdigit(getNext()))
						;
					break;
				}
				//This accepts a ({digit}+)
			} else
				break;
		}
	}

	return line.substr(columnPos, controlPointer - columnPos);
}

string LexicalAnalyzer::getOperator() {
	columnPos = controlPointer;

	if (getNext() == '=')
		getNext();

	return line.substr(columnPos, controlPointer - columnPos);
}

string LexicalAnalyzer::getDelimiter() {
	columnPos = controlPointer;
	getNext();
	return line.substr(columnPos, controlPointer - columnPos);
}

string LexicalAnalyzer::getCharacterDelimiter() {
	columnPos = controlPointer;

	char atual = line[controlPointer];

	if (atual == '\'') {
		atual = getNext();
		while (atual != '\'') {
			if (controlPointer == line.length() + 1) {
				cerr << "Error: Character Chain not delimited by ('''), line "
						<< linePos << endl;
				exit(1);
			}
			atual = getNext();
		}
	} else {
		atual = getNext();
		while (atual != '"') {
			if (controlPointer == line.length() + 1) {
				cerr
						<< "Error: Character String not delimited by ('\"'), line "
						<< linePos << endl;
				exit(1);
			}
			atual = getNext();
		}
	}

	getNext();

	return line.substr(columnPos, controlPointer - columnPos);
}

void LexicalAnalyzer::skipSpace() {
	getNext();
}

